package com.knowledge.review.designPatterns.behavioralpattern.interpreterpattern;

import lombok.AllArgsConstructor;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

// 抽象角色 定义解释器
public interface Expression {
    int interpret();
}

@AllArgsConstructor
class NumberTerminal implements Expression {
    private int number;

    @Override
    public int interpret() {
        return this.number;
    }
}

// 非终结表达式（抽象类）
@AllArgsConstructor
abstract class NonTerminal implements Expression {
    protected Expression left;
    protected Expression right;
}

// 非终结表达式（加法）
class PlusNonTerminal extends NonTerminal implements Expression {
    public PlusNonTerminal(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

// 非终结表达式（减法）
class MinusNonTerminal extends NonTerminal implements Expression {
    public MinusNonTerminal(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return left.interpret() - right.interpret();
    }
}

// 非终结表达式（乘法）
class MclNonTerminal extends NonTerminal implements Expression {
    public MclNonTerminal(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}

// 非终结表达式（除法）
class DivisionNonTerminal extends NonTerminal implements Expression {
    public DivisionNonTerminal(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return left.interpret() / right.interpret();
    }
}

// 计算器类（实现运算逻辑）
class Cal {
    private Expression left;
    private Expression right;
    private Integer result;

    public Cal(String expression) {
        this.parse(expression);
    }

    private Integer parse(String expression) {
        // 获取表达式元素
        String[] elements = expression.split(" ");
        for (int i = 0; i < elements.length; i++) {
            String element = elements[i];
            // 判断是否是运算符号
            if (OperatorUtils.isOperator(element)) {
                // 运算符号的右边就是右终结符
                right = new NumberTerminal(Integer.valueOf(elements[++i]));
                //计算结果
                result = OperatorUtils.getNonTerminal(left, right, element).interpret();
                // 计算结果重新成为左终结符
                left = new NumberTerminal(result);
            } else {
                left = new NumberTerminal(Integer.valueOf(element));
            }
        }
        return result;
    }

    public Integer cal() {
        return result;
    }

}

// 操作工具类
class OperatorUtils {
    // 判断是不是非终结符
    public static boolean isOperator(String symbol) {
        return symbol.equals("+") || symbol.equals("-") || symbol.equals("*") || symbol.equals("/");
    }

    // 简单工厂
    public static NonTerminal getNonTerminal(Expression left, Expression right, String symbol) {
        if (symbol.equals("+")) {
            return new PlusNonTerminal(left, right);
        } else if (symbol.equals("-")) {
            return new MinusNonTerminal(left, right);
        } else if (symbol.equals("*")) {
            return new MclNonTerminal(left, right);
        } else if (symbol.equals("/")) {
            return new DivisionNonTerminal(left, right);
        }
        return null;
    }
}

class Test {
    // 测试
    // PS：此处进行的逻辑仅仅实现从左到右运算，并没有先乘除后加减的逻辑
//    public static void main(String[] args) {
//        System.out.println(new Cal("10 + 20 - 40 * 60").cal());
//        // -600
//        System.out.println(new Cal("20 + 50 - 60 * 2").cal());
//        // 20
//    }


    /*
     *  下面是spring中的解释器，可以看到Spring中解释器写的是比较完善的，不仅有先乘除后加减和先括号进行运算的日常计算规则，而且对于空格也并没有要求，
     * 仅需要写出完整的表达式即可运算出来。
     */
    public static void main(String[] args) {
        ExpressionParser expressionParser = new SpelExpressionParser();
        org.springframework.expression.Expression expression = expressionParser.parseExpression("10 + 20 + 30 * 4");
        Integer value = expression.getValue(Integer.class);
        System.out.println(value); // 150
        expression = expressionParser.parseExpression("(10+20+30)*4");
        value = expression.getValue(Integer.class);
        System.out.println(value); // 240
    }
}